package com.youlu.campus.service.course;

import com.alibaba.fastjson.JSONObject;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.entity.ActivityQaInfo;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.entity.course.*;
import com.youlu.campus.entity.course.dto.CourseInfoDTO;
import com.youlu.campus.entity.course.dto.UserActivityDTO;
import com.youlu.campus.entity.course.vo.CourseInfoVo;
import com.youlu.campus.entity.course.vo.CourseVideoVo;
import com.youlu.campus.entity.enums.ActivityVideoStatusEnum;
import com.youlu.campus.entity.enums.CourseVideoEnum;
import com.youlu.campus.service.activity.UserActivityTaskInfoService;
import com.youlu.campus.service.qa.ActivityQaInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author : [dengbo]
 * @className : UserVideoService
 * @description : [用户视频服务]
 * @createTime : [2022/5/18 15:10]
 */
@Service
@Slf4j
public class UserVideoService {

    @Autowired
    private ActivityQaInfoService activityQaInfoService;

    @Autowired
    private UserActivityService userActivityService;

    @Autowired
    private MongoTemplate mongoTemplate;
    @Lazy
    @Autowired
    private UserActivityTaskInfoService userActivityTaskInfoService;

    public void saveUserVideo(CourseInfoDTO dto, int totalDuration) {
        // 查询用户课程
        UserCourseVideoStudy videoStudy = getCourseStudyByUserId(dto);
        if (videoStudy != null) {
            if (videoStudy.getStatus().equals(CourseVideoEnum.COMPLETE.getType())) {
                log.info("UserVideoService,saveUserVideo,userId={} video study complete", dto.getUserId());
                return;
            }
            if (dto.getVideoPlayType() != 2 && dto.getCurrentDuration() < videoStudy.getCurrentDuration()) {
                log.info("UserVideoService,saveUserVideo,userId={} current study time={} less has see time={}", dto.getUserId(),
                        dto.getCurrentDuration(), videoStudy.getCurrentDuration());
                return;
            }
        }
        // 课程是否学习完成
        boolean isComplete = dto.getVideoPlayType() == 2 || dto.getCurrentDuration() >= totalDuration;
        // 构建数据
        videoStudy = videoStudy == null ? buildUserCourseStudy(dto, totalDuration) : reBuildUserCourseStudy(videoStudy, dto.getCurrentDuration(), totalDuration);
        // 记录视频学习完成
        if (isComplete) {
            // 当前视频学习完成
            buildCompleteUserCourseStudy(videoStudy);
            // 处理视频学习完成活动状态
            // dealCompleteUserActivity(videoStudy);
            dealRedisCompleteUserActivity(videoStudy);
        }
        mongoTemplate.save(videoStudy);
    }

    /**
     * 处理完成的用户活动
     */
    public void dealCompleteUserActivity(UserCourseVideoStudy videoStudy) {
        // 1、查询完成学习课程
        long complete = getCompleteCourseVideoTotalNum(videoStudy);
        // 2、查询总的活动课程视频
        long total = mongoTemplate.count(new Query(Criteria.where("courseId").is(videoStudy.getCourseId()).and("valid").is(1)), ActivityCourseVideo.class);
        log.info("UserVideoService,dealCompleteUserActivity,userId:{} appId:{} videoId:{} complete num={} total num={}",
                videoStudy.getUserId(), videoStudy.getAppId(), videoStudy.getActivityId(), complete, total);
        if (complete + 1 >= total) {
            // 更新活动完成记录
            updateCompleteUserActivity(videoStudy.getUserId(), videoStudy.getAppId(), videoStudy.getActivityId());
        }
    }

    public long getCompleteCourseVideoTotalNum(UserCourseVideoStudy videoStudy) {
        // 1、查询完成学习课程
        return mongoTemplate.count(new Query(Criteria.where("userId").is(videoStudy.getUserId())
                .and("appId").is(videoStudy.getAppId()).and("courseId").is((videoStudy.getCourseId()))
                .and("status").is(CourseVideoEnum.COMPLETE.getType())), UserCourseVideoStudy.class);
    }

    /**
     * 处理完成的用户活动
     */
    public void dealRedisCompleteUserActivity(UserCourseVideoStudy videoStudy) {
        // 1、查询总的课程
        int total = (int) mongoTemplate.count(new Query(Criteria.where("courseId").is(videoStudy.getCourseId()).and("valid").is(1)), ActivityCourseVideo.class);
        // 2、查询总的活动课程视频
        if (userActivityService.hasStudyComplete(videoStudy.getCourseId(), videoStudy.getUserId(), total)) {
            // 更新活动完成记录
            updateCompleteUserActivity(videoStudy.getUserId(), videoStudy.getAppId(), videoStudy.getActivityId());
            log.info("UserVideoService,dealRedisCompleteUserActivity,userId:{} videoId:{} total:{} study success", videoStudy.getUserId(), videoStudy.getVideoId(), total);
        }
    }

    public void updateCompleteUserActivity(String userId, String appId, String activityId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId).and("appId").is(appId).and("activityId").is(activityId));
        Update update = new Update();
        update.set("status", ActivityVideoStatusEnum.DO_THE_TITLE.getType());
        update.set("studyCompleteTime", LocalDateTime.now());
        UpdateResult result = mongoTemplate.updateFirst(query, update, UserActivityCourse.class);
        log.info("UserVideoService,updateCompleteUserActivity,result:{}", JSONObject.toJSONString(result));
    }

    /**
     * 处理用户报名活动
     */
    public Triple<Boolean, Object, String> dealUserJoinActivity(String appId, String userId, String activityId, String courseId) {
        UserActivityCourse userActivityCourse = getUserActiveCourseByUser(userId, appId, activityId);
        if (userActivityCourse != null && (userActivityCourse.getJoined() || userActivityCourse.getStatus() > ActivityVideoStatusEnum.UN_LOCK_COURSE.getType())) {
            return Triple.of(false, null, "已经报名了");
        }
        if (userActivityCourse == null) {
            userActivityCourse = buildJoinActivityCourse(appId, userId, activityId, courseId);
        } else {
            userActivityCourse.setStatus(ActivityVideoStatusEnum.STUDYING.getType());
            userActivityCourse.setJoined(true);
        }
        // 查询题库信息
        ActivityQaInfo qaInfo = activityQaInfoService.findByActivityIdAndQaNumber(activityId, 1);
        if (qaInfo != null) {
            userActivityCourse.setQaInfoId(qaInfo.getId());
        }
        mongoTemplate.save(userActivityCourse);
        return Triple.of(true, null, "");
    }

    /**
     * 重置退款的用户活动信息和状态
     */
    public void dealRefundUserActivity(String userId, String appId, String activityId, String courseId) {
        // 重置课程学习
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId).and("appId").is(appId).and("courseId").is(courseId));
        Update update = new Update();
        update.set("status", CourseVideoEnum.NOT_START.getType());
        update.set("currentDuration", 0);
        mongoTemplate.updateMulti(query, update, UserCourseVideoStudy.class);
        // 重置活动信息
        Query activityQuery = new Query().addCriteria(Criteria.where("userId").is(userId).and("appId").is(appId).and("activityId").is(activityId));
        Update aupdate = new Update();
        aupdate.set("status", 0);
        aupdate.set("joined", false);
        mongoTemplate.updateFirst(activityQuery, aupdate, UserActivityCourse.class);
        // 重置活动完成数量
        userActivityService.delStudyCompleteNum(courseId, userId);
    }


    public UserCourseVideoStudy buildUserCourseStudy(CourseInfoDTO dto, int totalDuration) {
        UserCourseVideoStudy videoStudy = new UserCourseVideoStudy();
        videoStudy.setVideoId(dto.getVideoId());
        videoStudy.setCourseId(dto.getCourseId());
        videoStudy.setActivityId(dto.getActivityId());
        videoStudy.setUserId(dto.getUserId());
        videoStudy.setAppId(dto.getAppId());
        videoStudy.setStartTime(LocalDateTime.now());
        videoStudy.setCurrentDuration(dto.getCurrentDuration());
        videoStudy.setTotalDuration(totalDuration);
        videoStudy.setAppId(dto.getAppId());
        videoStudy.setStatus(CourseVideoEnum.STUDYING.getType());
        return videoStudy;
    }

    public UserCourseVideoStudy reBuildUserCourseStudy(UserCourseVideoStudy videoStudy, int currentDuration, int totalDuration) {
        if (videoStudy.getStatus().equals(CourseVideoEnum.NOT_START.getType())) {
            videoStudy.setStatus(CourseVideoEnum.STUDYING.getType());
            videoStudy.setStartTime(LocalDateTime.now());
        }
        videoStudy.setCurrentDuration(currentDuration);
        videoStudy.setTotalDuration(totalDuration);
        return videoStudy;
    }

    public UserCourseVideoStudy buildCompleteUserCourseStudy(UserCourseVideoStudy videoStudy) {
        videoStudy.setStatus(CourseVideoEnum.COMPLETE.getType());
        videoStudy.setEndTime(LocalDateTime.now());
        videoStudy.setCurrentDuration(videoStudy.getTotalDuration());
        return videoStudy;
    }

    public UserActivityCourse buildJoinActivityCourse(String appId, String userId, String activityId, String courseId) {
        UserActivityCourse activityCourse = new UserActivityCourse();
        activityCourse.setAppId(appId);
        activityCourse.setUserId(userId);
        activityCourse.setActivityId(activityId);
        activityCourse.setCourseId(courseId);
        activityCourse.setDeleted(false);
        activityCourse.setJoined(true);
        activityCourse.setStatus(ActivityVideoStatusEnum.STUDYING.getType());
        return activityCourse;
    }


    public UserActivityCourse getUserActiveCourseByUser(String userId, String appId, String activityId) {
        return mongoTemplate.findOne(new Query(Criteria.where("userId").is(userId).and("appId").is(appId)
                .and("activityId").is(activityId)), UserActivityCourse.class);
    }

    public UserActivityCourse insertActivityCourse(UserActivityCourse course) {
        return mongoTemplate.insert(course);
    }

    public UserCourseVideoStudy insert(UserCourseVideoStudy study) {
        return mongoTemplate.insert(study);
    }

    public List<UserCourseVideoStudy> getCourseStudyList(String userId, String appId, String courseId) {
        Query query = new Query(Criteria.where("userId").is(userId).and("appId").is(appId).and("courseId").is(courseId));
        return mongoTemplate.find(query, UserCourseVideoStudy.class);
    }

    public UserCourseVideoStudy getCourseVideoByVideoId(String userId, String appId, String courseId,String videoId) {
        Query query = new Query(Criteria.where("userId").is(userId).and("appId").is(appId).
                and("courseId").is(courseId).and("videoId").is(videoId));
        return mongoTemplate.findOne(query, UserCourseVideoStudy.class);
    }

    public List<UserActivityCourse> getUserActivityList(String userId, String appId) {
        Query query = new Query(Criteria.where("userId").is(userId).and("appId").is(appId));
        return mongoTemplate.find(query, UserActivityCourse.class);
    }
    /**
     * 获取小程序活动进行状态
     *
     * @return
     */
    public Integer getActivityStatus(String userId, String appId, String activityId) {
        if (StringUtils.isBlank(userId)) {
            return ActivityVideoStatusEnum.UN_LOCK_COURSE.getType();
        }
        // 1、查询活动课程记录
        Query query = new Query(Criteria.where("userId").is(userId).and("appId").is(appId).and("activityId").is(activityId));
        query.with(Sort.by(Sort.Direction.DESC,"status"));
        UserActivityCourse activityCourse = mongoTemplate.findOne(query, UserActivityCourse.class);
        return activityCourse == null ? ActivityVideoStatusEnum.UN_LOCK_COURSE.getType() : activityCourse.getStatus();
    }

    public UserActivityDTO getUserActivityInfo(String userId, String appId, String activityId) {
        UserActivityDTO dto = new UserActivityDTO();
        if (StringUtils.isBlank(userId)) {
            dto.setStatus(ActivityVideoStatusEnum.UN_LOCK_COURSE.getType());
            return dto;
        }
        // 1、查询活动课程记录
        Query query = new Query(Criteria.where("userId").is(userId).and("appId").is(appId).and("activityId").is(activityId));
        UserActivityCourse activityCourse = mongoTemplate.findOne(query, UserActivityCourse.class);
        if (activityCourse == null) {
            dto.setStatus(ActivityVideoStatusEnum.UN_LOCK_COURSE.getType());
            return dto;
        }
        dto.setStatus(activityCourse.getStatus());
        dto.setQaInfoId(activityCourse.getQaInfoId());
        // 扩展支持感悟类
        return dto;
    }

    public UserCourseVideoStudy getCourseStudyByUserId(CourseInfoDTO dto) {
        // 查询用户课程
        Query query = new Query(Criteria.where("userId").is(dto.getUserId()).and("appId").is(dto.getAppId()).and("courseId").is(dto.getCourseId())
                .and("videoId").is(dto.getVideoId()));
        return mongoTemplate.findOne(query, UserCourseVideoStudy.class);
    }

    /**
     * 设置视频学习状态
     *
     * @return
     */
    public void setVideoStudyStatus(CourseInfoDTO dto, CourseInfoVo courseInfoVo) {
        UserPO userPO = dto.getUserPO();
        int status = courseInfoVo.getActivityStatus();
        List<CourseVideoVo> list = courseInfoVo.getVideoVoList();
        AtomicInteger studyVideoNum = new AtomicInteger();
        if (StringUtils.isBlank(dto.getUserId()) || status < ActivityVideoStatusEnum.STUDYING.getType()) {
            list.forEach(item -> {
                //不等于试看
                if(item.getTryPlay()!=2){
                    item.setStatus(CourseVideoEnum.NOT_START.getType());
                    item.setCurrentDuration(0);
                }else{
                    List<UserCourseVideoStudy> videoStudies = getCourseStudyList(dto.getUserId(), userPO.getAppId(), courseInfoVo.getCourseId());
                    Map<String, UserCourseVideoStudy> map = videoStudies.stream().collect(Collectors.toMap(item2 -> item2.getVideoId(), Function.identity(), (o1, o2) -> o1));
                    UserCourseVideoStudy study = map.get(item.getId());
                    item.setStatus(study == null ? CourseVideoEnum.NOT_START.getType() : study.getStatus());
                    item.setCurrentDuration(study == null ? 0 : study.getCurrentDuration());
                    if (CourseVideoEnum.COMPLETE.getType() == item.getStatus()) {
                        studyVideoNum.incrementAndGet();
                    }
                }

            });
            //设置学习进度
            courseInfoVo.setStudyVideo(studyVideoNum.get());
            return;
        }
        if (status >= ActivityVideoStatusEnum.DO_THE_TITLE.getType()) {
            list.forEach(item -> {
                item.setStatus(CourseVideoEnum.COMPLETE.getType());
                item.setCurrentDuration(0);
            });
            courseInfoVo.setStudyVideo(courseInfoVo.getTotalVideo());
            return;
        }
        List<UserCourseVideoStudy> videoStudies = getCourseStudyList(dto.getUserId(), userPO.getAppId(), courseInfoVo.getCourseId());
        Map<String, UserCourseVideoStudy> map = videoStudies.stream().collect(Collectors.toMap(item -> item.getVideoId(), Function.identity(), (o1, o2) -> o1));

        if (courseInfoVo.getTotalVideo() > 0) {
            for (CourseVideoVo item : list) {
                UserCourseVideoStudy study = map.get(item.getId());
                item.setStatus(study == null ? CourseVideoEnum.NOT_START.getType() : study.getStatus());
                item.setCurrentDuration(study == null ? 0 : study.getCurrentDuration());
                if (CourseVideoEnum.COMPLETE.getType() == item.getStatus()) {
                    studyVideoNum.incrementAndGet();
                }
            }
            //设置学习进度
            courseInfoVo.setStudyVideo(studyVideoNum.get());
            //观看学习完成并且学习数量大于总数
            if (studyVideoNum.get() >= courseInfoVo.getTotalVideo()) {
                courseInfoVo.setActivityStatus(ActivityVideoStatusEnum.DO_THE_TITLE.getType());
                //视频学习完成，更新状态
                updateCompleteUserActivity(dto.getUserId(), dto.getAppId(), dto.getActivityId());
                //删除redis学习总数记录
                userActivityService.delStudyCompleteNum(dto.getCourseId(),dto.getUserId());
            }
        }
    }

    /**
     * 更行用户状态机流程
     *
     * @param currentUser
     * @param activityId
     * @param activityId
     * @param originStatus
     * @param targetStatus
     * @param qaInfoId
     */
    @Async
    public void updateStatusUserActivityCourse(UserPO currentUser, String activityId,
                                               String qaInfoId, Integer originStatus,
                                               Integer targetStatus) {
        log.info("【用户参与活动状态变更】userId - > {} |activityId-> {}|originStatus-> {}|targetStatus-> {}", currentUser.getId(),
                activityId, originStatus, targetStatus);
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(currentUser.getId()));
        query.addCriteria(Criteria.where("appId").is(currentUser.getAppId()));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        query.addCriteria(Criteria.where("status").is(originStatus));
        Update update = new Update();
        update.set("status", targetStatus);
        update.set("updatedTime", new Date());
        update.set("qaInfoId", qaInfoId);
        this.mongoTemplate.updateFirst(query, update, UserActivityCourse.class);
    }
}
